#include <errno.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
//#include <wchar.h>
#include <string.h>

#include <aura.h>
#include <auraplus.h>
#include <linknode.h>
#include <aura_wchar.h>

#undef NULL

#include "private.h"


Aura_ProcessId g_processId = 0;

extern void _AllThread_Kill();
EXTERN void _AllThread_SetPriority(Aura_ThreadPriorityRank PriorityRank);
EXTERN void _AllThread_GetPriority(Aura_ThreadPriorityRank *pPriorityRank);

AURA_API_(Aura_ProcessId) AuraProcess_GetCurrentId()
{
    return g_processId;
}

AURA_API_(Aura_Void) AuraProcess_Exit(
        /* [in] */ Aura_ExitCode exitCode)
{
    FixMe("Not implemented yet.");
    //return AURA_E_NOT_IMPLEMENTED;
    _exit((int)exitCode);
}

AURA_API AuraProcess_GetStartInfo(
        /* [out] */ Aura_PWChar pwImageName,
        /* [out] */ Aura_PWChar pwArguments)
{
FixMe("Not implemented yet.");
    return AURA_NOERROR;
}

AURA_API AuraProcess_GetPriorityRank(//current
        /* [out] */ Aura_ThreadPriorityRank * pPriorityRank)
{

    _AllThread_GetPriority(pPriorityRank);
    return AURA_NOERROR;
}

AURA_API AuraProcess_SetPriorityRank(
        /* [out] */ Aura_ThreadPriorityRank priorityRank)
{
    _AllThread_SetPriority(priorityRank);
    return AURA_NOERROR;
}

AURA_API AuraProcess_GetProcessorTimes(
        /* [out] */ Aura_Millisecond32 * pUserTime,
        /* [out] */ Aura_Millisecond32 * pPrivilegedTime)
{
    struct rusage usage;
    int ret;

    if((NULL == pUserTime)
        || (NULL == pPrivilegedTime))
    {
        PERROR("Error: Get Process Processor Time failed! \
        file:%s. line:%d. \n",
        __FILE__, __LINE__);
        return AURA_E_INVALID_ARGUMENT;
    }

    ret = getrusage(RUSAGE_SELF, &usage);
    if(-1 == ret){
        PERROR("Error: Get Process Processor Time failed! error number:%d.\
        errno, file:%s. line:%d. \n",
        __FILE__, __LINE__);
        return AURA_E_INVALID_OPERATION;
    }

    *pUserTime = usage.ru_utime.tv_sec*1000 + usage.ru_utime.tv_usec/1000;
    *pPrivilegedTime = usage.ru_stime.tv_sec*1000 + usage.ru_stime.tv_usec/1000;

    return AURA_NOERROR;
}

AURA_API AuraProcess_GetMemoryInformation(
        /* [out] */ Aura_Int32 * pPrivateVirtualMemorySize,
        /* [out] */ Aura_Int32 * pSharedVirtualMemorySize,
        /* [out] */ Aura_Int32 * pPrivatePhysicalMemorySize,
        /* [out] */ Aura_Int32 * pSharedPhysicalMemorySize)
{
    char szProcStatm[AURA_MAX_PATH];
    char szStatm[AURA_MAX_PATH];
    int iReadSize;
    int fdStatm;
    int iPhysicalPages = 0;
    int iPhysicalResident = 0;
    int iPhysicalShare = 0;
    int iPhysicalTrs = 0;
    int iPhysicalLrs = 0;
    int iPhysicalDrs = 0;
    int iPhysicalDt = 0;


//    sprintf(szProcStatm, "/proc/%d/statm", (int)hProcess);

    fdStatm = open(szProcStatm, O_RDONLY);
    if(-1 == fdStatm){
        PERROR("Error: Get Memory information failed! errno%d. \
        file:%s. line:%d. \n",
        errno, __FILE__, __LINE__);
        return AURA_E_INVALID_OPERATION;
    }

    memset(szStatm, 0, AURA_MAX_PATH);

    iReadSize = read(fdStatm, szStatm, AURA_MAX_PATH);
    if(-1 == iReadSize){
        PERROR("Error: Get Memory information failed! errno%d. \
        file:%s. line:%d. \n",
        errno, __FILE__, __LINE__);
        close(fdStatm);
        return AURA_E_INVALID_OPERATION;
    }

    PTRACE("szStatm:%s\n", szStatm);

    sscanf(szStatm, "%d %d %d %d %d %d %d\n",
        &iPhysicalPages,
        &iPhysicalResident,
        &iPhysicalShare,
        &iPhysicalTrs,
        &iPhysicalLrs,
        &iPhysicalDrs,
        &iPhysicalDt);

    if(NULL != pPrivateVirtualMemorySize){
        *pPrivateVirtualMemorySize
            = (iPhysicalPages - iPhysicalShare) * _PAGE_SIZE;
    }
    if(NULL != pSharedVirtualMemorySize){
        *pSharedVirtualMemorySize = iPhysicalShare * _PAGE_SIZE;
    }
    if(NULL != pPrivatePhysicalMemorySize){
        *pPrivatePhysicalMemorySize
            = (iPhysicalPages - iPhysicalShare) * _PAGE_SIZE;
    }
    if(NULL != pSharedPhysicalMemorySize){
        *pSharedPhysicalMemorySize = iPhysicalShare * _PAGE_SIZE;
    }

    close(fdStatm);

    return AURA_NOERROR;
}

